﻿using AspNetCore.Web.Librs;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Configuration;
using AspNetCore.Web.Config;
using AspNetCore.Web.Caching;
using AspNetCore.Web.Security;
using Microsoft.AspNetCore.DataProtection;
using System.IO;
using AspNetCore.Web.Infrastructure;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// IServiceCollection 容器的拓展类
    /// </summary>
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 程序集依赖注入。读取程序中的接口和实现 注入Asp.net core 容器
        /// </summary>
        /// <param name="services"></param>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="serviceLifetime"></param>
        public static void AddAssembly(this IServiceCollection services, string assemblyName, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services) + "为空");

            if (String.IsNullOrEmpty(assemblyName))
                throw new ArgumentNullException(nameof(assemblyName) + "为空");

            var assembly = RuntimeHelper.GetAssemblyByName(assemblyName);

            if (assembly == null)
                throw new DllNotFoundException(nameof(assembly) + ".dll不存在");

            var types = assembly.GetTypes();
            var list = types.Where(o => o.IsClass && !o.IsAbstract && !o.IsGenericType).ToList();
            if (list == null && !list.Any())
                return;
            foreach (var type in list)
            {
                var interfacesList = type.GetInterfaces();
                if (interfacesList == null || !interfacesList.Any())
                    continue;
                var inter = interfacesList.First();
                switch (serviceLifetime)
                {
                    case ServiceLifetime.Scoped:
                        services.AddScoped(inter, type);
                        break;
                    case ServiceLifetime.Singleton:
                        services.AddSingleton(inter, type);
                        break;
                    case ServiceLifetime.Transient:
                        services.AddTransient(inter, type);
                        break;
                }
            }
        }

        /// <summary>
        /// 配置文件扩展，创建配置对象，并注入
        /// </summary>
        /// <typeparam name="TConfig"></typeparam>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static TConfig ConfigureStartupConfig<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
        {
            var config = new TConfig();

            configuration.Bind(config);

            services.AddSingleton(config);

            return config;
        }

        /// <summary>
        /// 启用redis或内存缓存
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddRedisOrMemoryCache(this IServiceCollection services, IConfiguration configuration)
        {
            var config = services.ConfigureStartupConfig<CacheConfig>(configuration.GetSection("CacheConfig"));
            if (config.RedisCachingEnabled)
            {
                services.AddSingleton<IRedisConnectionWrapper, RedisConnectionWrapper>();
                services.AddSingleton<ICacheManager, RedisCacheManager>();
            }
            else
                services.AddSingleton<ICacheManager, MemoryCacheManager>();
        }

        /// <summary>
        /// 启用后台cookie验证
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        [Obsolete("2.0.6 弃用，启用：AddAdminSecurity 即可")]
        public static void AddAdminAuthentication(this IServiceCollection services, IConfiguration configuration)
        {
            var config = services.ConfigureStartupConfig<AspNetCoreConfig>(configuration.GetSection("AspNetCoreConfig"));
            services.AddAuthentication(o =>
            {
                o.DefaultAuthenticateScheme = CookieAdminAuthInfo.AuthenticationScheme;
                o.DefaultChallengeScheme = CookieAdminAuthInfo.AuthenticationScheme;
            }).AddCookie(CookieAdminAuthInfo.AuthenticationScheme, o =>
            {
                o.Cookie.Domain = config.Domain;
                o.Cookie.Name = CookieAdminAuthInfo.CookiePrefix + CookieAdminAuthInfo.AuthenticationScheme;
            });
        }

        /// <summary>
        /// 添加身份加密keys 的自定义目录。保存到项目跟目录下的keys目录。
        /// </summary>
        /// <param name="services"></param>
        public static void AddKeysProtection(this IServiceCollection services) {
                services.AddDataProtection()
               .SetApplicationName(DataProtection.AppName)
               .SetDefaultKeyLifetime(TimeSpan.FromDays(100 * 360))
               .PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), "keys")));
        }


    }
}
